/*
 *  Copyright 2008 Mark Ashworth <javameme@gmail.com>.
 * 
 *  Licensed under the GNU General Public License v3 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.gnu.org/licenses/gpl-3.0.html
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package xperiment.metaphor.model.entity;

import java.text.SimpleDateFormat;
import java.util.Date;

import metaphor.service.ServiceException;
import xperiment.metaphor.model.DomainObject;
import xperiment.metaphor.model.ModelException;
import xperiment.metaphor.model.Persistent;
import xperiment.metaphor.model.SaveException;
import xperiment.metaphor.model.XML;

/**
 * The authentication events when users are authenticated in the system.
 * @author Mark Ashworth <javameme@gmail.com>
 * @version 1.0.0
 * @since 1.0.0
 */
//@Entity
//@Table(name="authentication_event")
public class AuthenticationEvent extends DomainObject implements Persistent, XML {

    //@Id @GeneratedValue(strategy=GenerationType.AUTO)
    //@Column(name = "authentication_event_id", unique = true, nullable = false)
    private Long id = null;
    
    /* The date and time the event occurred */
    //@Column(name="event_time", nullable=true)
    private Date eventTime;
    
    /* The status of the event, typically FAILED, SUCCESS */
    //@Column(name="status", unique=false, nullable=true, length=25)
    private String status;
    
    /* The user name for which the authentication event was generated */
    //@Column(name="user_name", unique=false, nullable=false, length=25)
    private String userName;
    
    /* The additional details about the authentication request */
    //@Column(name="details", unique=false, nullable=true, length=4096)
    private String details;
    
    /* The exception that caused the authentication event */
    //@Column(name="exception", unique=false, nullable=true, length=4096)
    private String exception;

    /** The remote address of the user */
    //@Column(name="remote_address", unique=false, nullable=true, length=255)
    private String remoteAddress;

    /** The session of the authentication event */
    //@Column(name="session", unique=false, nullable=true, length=255)
    private String session;

    /* Whether the event is enabled */
    //@Column(name = "enabled", nullable = false)
    private boolean enabled = true;
    
    /**
     * Default constructor
     */
    public AuthenticationEvent() {
        super();
    }

    /**
     * Constructs an authentication event
     * @param eventTime The date and time the event occurred
     * @param status The status of the event, typically FAILED, SUCCESS
     * @param userName The user name for which the authentication event was generated
     * @param details The additional details about the authentication request
     * @param exception The exception that caused the authentication event
     */
    public AuthenticationEvent(
            Date eventTime, 
            String status, 
            String userName, 
            String details, 
            String exception) {
        this.eventTime = eventTime;
        this.status = status;
        this.userName = userName;
        this.details = details;
        this.exception = exception;
    }

    /**
     * Constructs an authentication event
     * @param eventTime The date and time the event occurred
     * @param status The status of the event, typically FAILED, SUCCESS
     * @param userName The user name for which the authentication event was generated
     * @param details The additional details about the authentication request
     * @param exception The exception that caused the authentication event
     */
    public AuthenticationEvent(
            Date eventTime,
            String status,
            String userName,
            String details,
            String exception,
            String remoteAddress,
            String session) {
        this.eventTime = eventTime;
        this.status = status;
        this.userName = userName;
        this.details = details;
        this.exception = exception;
        this.remoteAddress = remoteAddress;
        this.session = session;
    }

    /**
     * The unique database id for the object
     * @return long
     */
	public Long getId() {
		return this.id;
	}
    
    /**
     * The date and time the event occurred
     * @return Date
     */
    public Date getEventTime() {
        return eventTime;
    }
    
    /**
     * The user name for which the authentication event was generated
     * @return String
     */
    public String getUserName() {
        return userName;
    }
    
    /**
     * The status of the event, typically FAILED, SUCCESS
     * @return String
     */
    public String getStatus() {
        return status;
    }
    
    /**
     * The additional details about the authentication request
     * @return String
     */
    public String getDetails() {
        return details;
    }

    /**
     * The exception that caused the authentication event
     * @return String
     */
    public String getException() {
        return exception;
    }

    /**
     * Remote address
     * @return String
     */
    public String getRemoteAddress() {
        return remoteAddress;
    }

    /**
     * Session
     * @return String
     */
    public String getSession() {
        return session;
    }

    /**
     * Whether the event is enabled
     * @return boolean
     */
    public boolean isEnabled() {
        return this.enabled;
    }

    /**
     * Saves the authentication event
     * @throws SaveException If the event could not be saved
     */
    public AuthenticationEvent save() throws ModelException {
        
        try {
            AuthenticationEvent e = (AuthenticationEvent) getDao().persist(this);
            this.id = e.getId();
            return this;
        } catch (ServiceException e) {
            throw new SaveException("Unable to save authentication event", e);
        }
    }

    /**
     * Returns the String representation of the event<br />
     * Example: <br />
     * marka : SUCCESSFUL : 2008-06-10 23:43:45 : /login.html<br />
     * 
     * @return String
     */
    @Override
    public String toString() {
        final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        return 
                getUserName()
                + " : " + getStatus()
                + getEventTime() == null ? "" : " : " + df.format(getEventTime())
                + " : " + getDetails();
    }

    /**
     * Returns the XML representation of the event<br />
     * &lt;authentication_event id="1" event_time="2008-06-10 23:34"  status="SUCCESS" user_name="marka" &gt;<br />
     * &lt;details&gt;&lt;![CDATA[Some text]]&gt;&lt/details&gt;<br />
     * &lt;exception&gt;&lt;![CDATA[Some exception stack trace]]&gt;&lt/exception&gt;<br />
     * &lt;/authentication_event&gt;<br />
     * @return String
     */
    public String toXML() {
        final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        return "<authentication_event class='" + getClass().getName() 
                + "' id='" + getId() 
                + (getEventTime() == null ? "" : "' event_time='" + df.format(getEventTime())) 
                + "' status='" + getStatus() 
                + "' user_name='" + getUserName()
                + "' session='" + getSession()
                + "' remote_address='" + getRemoteAddress()
                + "' >"
                + (getDetails() == null ? "" : "<details><![CDATA[" + getDetails() + "]]></details>")
                + (getException() == null ? "" : "<exception><![CDATA[" + getException() + "]]></exception>")
                + "</authentication_event>";
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AuthenticationEvent other = (AuthenticationEvent) obj;
        if (this.eventTime != other.eventTime && (this.eventTime == null || !this.eventTime.equals(other.eventTime))) {
            return false;
        }
        if (this.status != other.status && (this.status == null || !this.status.equals(other.status))) {
            return false;
        }
        if (this.userName != other.userName && (this.userName == null || !this.userName.equals(other.userName))) {
            return false;
        }
        if (this.details != other.details && (this.details == null || !this.details.equals(other.details))) {
            return false;
        }
        return !(this.exception != other.exception && (this.exception == null || !this.exception.equals(other.exception)));
        }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 47 * hash + (this.eventTime != null ? this.eventTime.hashCode() : 0);
        hash = 47 * hash + (this.status != null ? this.status.hashCode() : 0);
        hash = 47 * hash + (this.userName != null ? this.userName.hashCode() : 0);
        hash = 47 * hash + (this.details != null ? this.details.hashCode() : 0);
        hash = 47 * hash + (this.exception != null ? this.exception.hashCode() : 0);
        return hash;
    }  
}
